#include "pluginmodel.h"

#include <QDebug>
#include <QSettings>

#include "pluginmanager.h"
struct PluginModelData {
  QString iid;
  QString name;
  bool loaded;
  QString version;
  QString author;

  QVariant getData(int index) const {
    QVariant value;
    switch (index) {
    case PluginModel::Column_Name:
      value = name;
      break;
    case PluginModel::Column_Loaded:
      value = loaded;
      break;
    case PluginModel::Column_Version:
      value = version;
      break;
    case PluginModel::Column_Author:
      value = author;
      break;
    }
    return value;
  }

  void setData(int index, const QVariant &value) {
    if (index == PluginModel::Column_Loaded) {
      loaded = value.toBool();
      QSettings settings("config.ini", QSettings::IniFormat);
      settings.beginGroup("plugins");

      settings.setValue(iid, loaded);
      settings.endGroup();
    }
  }
};

class PluginModelPrivate {
public:
  PluginModelPrivate(const PluginManager *const pluginManager, PluginModel *q)
      : q_ptr(q), pluginManager(pluginManager) {
    headData.append(R"(Name)");
    headData.append(R"(Load)");
    headData.append(R"(Version)");
    headData.append(R"(Author)");

    for (auto const &i : pluginManager->getPluginMetaData()) {
      PluginModelData modelData;
      modelData.iid = i.IID;
      modelData.loaded = pluginManager->isLoad(i.IID);
      modelData.name = i.name;
      modelData.version = i.version;
      modelData.author = i.author;

      modelDataList.append(modelData);
    }
  }

private:
  class PluginModel *const q_ptr;
  Q_DECLARE_PUBLIC(PluginModel)

  const PluginManager *const pluginManager;
  QStringList headData;
  QList<PluginModelData> modelDataList;
};
//==========================================================
PluginModel::PluginModel(const PluginManager *const pluginManager,
                         QObject *parent)
    : QAbstractTableModel(parent),
      d_ptr(new PluginModelPrivate(pluginManager, this)) {}

PluginModel::~PluginModel() { delete d_ptr; }

QVariant PluginModel::headerData(int section, Qt::Orientation orientation,
                                 int role) const {
  Q_D(const PluginModel);
  QVariant value;
  if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
    if (section >= 0 && section < columnCount())
      value = d->headData.at(section);
  }

  return value;
}

int PluginModel::rowCount(const QModelIndex &parent) const {
  if (parent.isValid())
    return 0;
  Q_D(const PluginModel);
  return d->modelDataList.count();
}

int PluginModel::columnCount(const QModelIndex &parent) const {
  if (parent.isValid())
    return 0;

  return PLUGINMODEL_MAX_COLUMN + 1;
}

Qt::ItemFlags PluginModel::flags(const QModelIndex &index) const {
  if (!index.isValid())
    return QAbstractTableModel::flags(index);

  Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
  if (index.column() == Column_Loaded)
    flags |= Qt::ItemIsUserCheckable;

  return flags;
}

QVariant PluginModel::data(const QModelIndex &index, int role) const {
  if (!index.isValid())
    return QVariant();

  Q_D(const PluginModel);
  QVariant value;

  switch (role) {
  case Qt::DisplayRole:
    if (index.column() != Column_Loaded)
      value = d->modelDataList.at(index.row()).getData(index.column());
    break;

//  case Qt::TextAlignmentRole:
//    value = Qt::AlignCenter;
//    break;
  case Qt::CheckStateRole:
    if (index.column() == Column_Loaded) {
      d->modelDataList.at(index.row()).getData(index.column()).toBool();

      value = d->modelDataList.at(index.row()).getData(index.column()).toBool()
                  ? Qt::Checked
                  : Qt::Unchecked;
    }
    break;
  }
  return value;
}

bool PluginModel::setData(const QModelIndex &index, const QVariant &value,
                          int role) {
  Q_D(PluginModel);
  if (!index.isValid())
    return false;

  int column = index.column();
  if (column == Column_Loaded) {
    if (role == Qt::CheckStateRole) {
      //更新选中行
      d->modelDataList[index.row()].setData(column, value);
      emit dataChanged(index, index);
      return true;
    }
  }

  return false;
}
